Next: Formatting Lisp Functions, Previous: Vector Lisp Functions, Up: Internals [Contents][Index]
The functions described here operate on symbolic formulas in the Calculator.
Prepare a stack entry for selection operations. If
num is omitted, the stack entry containing the
cursor is used; otherwise, it is the number of the stack
entry to use. This function stores useful information about
the current stack entry into a set of variables.
calc-selection-cache-num contains the number of
the stack entry involved (equal to num if you
specified it); calc-selection-cache-entry
contains the stack entry as a list (such as
calc-top-list would return with
entry as the selection mode); and
calc-selection-cache-comp contains a special
“tagged” composition (see Formatting
Lisp Functions) which allows Calc to relate cursor
positions in the buffer with their corresponding
sub-formulas.
A slight complication arises in the selection mechanism
because formulas may contain small integers. For example, in
the vector ‘[1, 2, 1]’ the first and
last elements are eq to each other; selections
are recorded as the actual Lisp object that appears somewhere
in the tree of the whole formula, but storing 1
would falsely select both 1’s in the
vector. So calc-prepare-selection also checks
the stack entry and replaces any plain integers with
“complex number” lists of the form
‘(cplx n 0)’. This list
will be displayed the same as a plain n and the
change will be completely invisible to the user, but it will
guarantee that no two sub-formulas of the stack entry will be
eq to each other. Next time the stack entry is
involved in a computation, calc-normalize will
replace these lists with plain numbers again, again invisibly
to the user.
This modifies the formula x to ensure that each
part of the formula is a unique atom, using the
‘(cplx n 0)’ trick
described above. This function may use setcar to
modify the formula in-place.
Find the smallest sub-formula of the current formula that
contains the cursor. This assumes
calc-prepare-selection has been called already.
If the cursor is not actually on any part of the formula,
this returns nil.
Change the currently prepared stack element’s
selection to selection, which should be
eq to some sub-formula of the stack element, or
nil to unselect the formula. The stack
element’s appearance in the Calc buffer is adjusted to
reflect the new selection.
Return the nth sub-formula of expr.
This function is used by the selection commands, and (unless
j b has been used) treats sums and products as
flat many-element formulas. Thus if expr is
‘((a + b) - c) + d’, calling
calc-find-nth-part with n equal to
four will return ‘d’.
Return the sub-formula of expr which
immediately contains part. If expr is
‘a*b + (c+1)*d’ and part
is eq to the ‘c+1’ term
of expr, then this function will return
‘(c+1)*d’. If part turns
out not to be a sub-formula of expr, the function
returns nil. If part is
eq to expr, the function returns
t. This function does not take associativity
into account.
This is the same as calc-find-parent-formula,
except that (unless j b has been used) it
continues widening the selection to contain a complete level
of the formula. Given ‘a’ from
‘((a + b) - c) + d’,
calc-find-parent-formula will return
‘a + b’ but
calc-find-assoc-parent-formula will return the
whole expression.
This expands sub-formula part of expr to encompass a complete level of the formula. If part and its immediate parent are not compatible associative operators, or if j b has been used, this simply returns part.
This finds the immediate sub-formula of expr
which contains part. It returns an index
n such that ‘(calc-find-nth-part
expr n)’ would return
part. If part is not a sub-formula of
expr, it returns nil. If
part is eq to expr, it
returns t. This function does not take
associativity into account.
This function returns a copy of formula expr,
with the sub-formula that is eq to
old replaced by new.
Simplify the expression expr by applying Calc’s algebraic simplifications. This always returns a copy of the expression; the structure expr points to remains unchanged in memory.
More precisely, here is what simplify does:
The expression is first normalized and evaluated by calling
normalize. If any AlgSimpRules have
been defined, they are then applied. Then the expression is
traversed in a depth-first, bottom-up fashion; at each level,
any simplifications that can be made are made until no
further changes are possible. Once the entire formula has
been traversed in this way, it is compared with the original
formula (from before the call to normalize) and,
if it has changed, the entire procedure is repeated (starting
with normalize) until no further changes occur.
Usually only two iterations are needed: one to simplify the
formula, and another to verify that no further
simplifications were possible.
Simplify the expression expr, with additional
rules enabled that help do a more thorough job, while not
being entirely “safe” in all circumstances. (For
example, this mode will simplify
‘sqrt(x^2)’ to
‘x’, which is only valid when
x is positive.) This is implemented by temporarily
binding the variable math-living-dangerously to
t (using a let form) and calling
simplify. Dangerous simplification rules are
written to check this variable before taking any action.
Simplify the expression expr, treating variable
names as units whenever possible. This works by binding the
variable math-simplifying-units to
t while calling simplify.
Register a new simplification rule; this is normally
called as a top-level form, like defun or
defmath. If funcs is a symbol (like
+ or calcFunc-sqrt), this
simplification rule is applied to the formulas which are
calls to the specified function. Or, funcs can be
a list of such symbols; the rule applies to all functions on
the list. The body is written like the body of a
function with a single argument called expr. The
body will be executed with expr bound to a
formula which is a call to one of the functions
funcs. If the function body returns
nil, or if it returns a result
equal to the original expr, it is
ignored and Calc goes on to try the next simplification rule
that applies. If the function body returns something
different, that new formula is substituted for
expr in the original formula.
At each point in the formula, rules are tried in the order
of the original calls to math-defsimplify; the
search stops after the first rule that makes a change. Thus
later rules for that same function will not have a chance to
trigger until the next iteration of the main
simplify loop.
Note that, since defmath is not being used
here, body must be written in true Lisp code
without the conveniences that defmath provides.
If you prefer, you can have body simply call
another function (defined with defmath) which
does the real work.
The arguments of a function call will already have been simplified before any rules for the call itself are invoked. Since a new argument list is consed up when this happens, this means that the rule’s body is allowed to rearrange the function’s arguments destructively if that is convenient. Here is a typical example of a simplification rule:
(math-defsimplify calcFunc-arcsinh
(or (and (math-looks-negp (nth 1 expr))
(math-neg (list 'calcFunc-arcsinh
(math-neg (nth 1 expr)))))
(and (eq (car-safe (nth 1 expr)) 'calcFunc-sinh)
(or math-living-dangerously
(math-known-realp (nth 1 (nth 1 expr))))
(nth 1 (nth 1 expr)))))
This is really a pair of rules written with one
math-defsimplify for convenience; the first
replaces ‘arcsinh(-x)’ with
‘-arcsinh(x)’, and the second, which
is safe only for real ‘x’, replaces
‘arcsinh(sinh(x))’ with
‘x’.
Check expr to see if it is a sum of terms all
multiplied by the same rational value. If so, return this
value. If not, return nil. For example, if
called on ‘6x + 9y + 12z’, it would
return 3, since 3 is a common factor of all the terms.
Assuming expr is a sum with factor as a common factor, divide each term of the sum by factor. This is done by destructively modifying parts of expr, on the assumption that it is being used by a simplification rule (where such things are allowed; see above). For example, consider this built-in rule for square roots:
(math-defsimplify calcFunc-sqrt
(let ((fac (math-common-constant-factor (nth 1 expr))))
(and fac (not (eq fac 1))
(math-mul (math-normalize (list 'calcFunc-sqrt fac))
(math-normalize
(list 'calcFunc-sqrt
(math-cancel-common-factor
(nth 1 expr) fac)))))))
Compute a “rational GCD” of a and
b, which must both be rational numbers. This is
the fraction composed of the GCD of the numerators of
a and b, over the GCD of the
denominators. It is used by
common-constant-factor. Note that the standard
gcd function uses the LCM to combine the
denominators.
Try applying Lisp function func to various
sub-expressions of expr. Initially, call
func with expr itself as an argument.
If this returns an expression which is not equal
to expr, apply func again until
eventually it does return expr with no changes.
Then, if expr is a function call, recursively
apply func to each of the arguments. This keeps
going until no changes occur anywhere in the expression; this
final expression is returned by map-tree. Note
that, unlike simplification rules, func functions
may not make destructive changes to expr.
If a third argument many is provided, it is an
integer which says how many times func may be
applied; the default, as described above, is infinitely many
times.
Compile the rewrite rule set specified by
rules, which should be a formula that is either a
vector or a variable name. If the latter, the compiled rules
are saved so that later compile-rules calls for
that same variable can return immediately. If there are
problems with the rules, this function calls
error with a suitable message.
Apply the compiled rewrite rule set crules to
the expression expr. This will make only one
rewrite and only checks at the top level of the expression.
The result nil if no rules matched, or if the
only rules that matched did not actually change the
expression. The heads argument is optional; if is
given, it should be a list of all function names that (may)
appear in expr. The rewrite compiler tags each
rule with the rarest-looking function name in the rule; if
you specify heads, apply-rewrites can
use this information to narrow its search down to just a few
rules in the rule set.
Compute a heads list for expr
suitable for use with apply-rewrites, as
discussed above.
This is an all-in-one rewrite function. It compiles the
rule set specified by rules, then uses
map-tree to apply the rules throughout
expr up to many (default infinity)
times.
Given a Calc vector vec and an uncompiled
pattern set or pattern set variable pat, this
function returns a new vector of all elements of
vec which do (or don’t, if
not-flag is non-nil) match any of the
patterns in pat.
Compute the derivative of expr with respect to
variable var (which may actually be any
sub-expression). If value is specified, the
derivative is evaluated at the value of var;
otherwise, the derivative is left in terms of var.
If the expression contains functions for which no derivative
formula is known, new derivative functions are invented by
adding primes to the names; see Calculus. However, if
symb is non-nil, the presence of
nondifferentiable functions in expr instead
cancels the whole differentiation, and deriv
returns nil instead.
Derivatives of an n-argument function can be
defined by adding a math-derivative-n
property to the property list of the symbol for the
function’s derivative, which will be the function name
followed by an apostrophe. The value of the property should
be a Lisp function; it is called with the same arguments as
the original function call that is being differentiated. It
should return a formula for the derivative. For example, the
derivative of ln is defined by
(put 'calcFunc-ln\' 'math-derivative-1
(function (lambda (u) (math-div 1 u))))
The two-argument log function has two
derivatives,
(put 'calcFunc-log\' 'math-derivative-2 ; d(log(x,b)) / dx
(function (lambda (x b) ... )))
(put 'calcFunc-log\'2 'math-derivative-2 ; d(log(x,b)) / db
(function (lambda (x b) ... )))
Compute the total derivative of expr. This is
the same as deriv, except that variables other
than var are not assumed to be constant with
respect to var.
Compute the integral of expr with respect to var. See Calculus, for further details.
Define a rule for integrating a function or functions of
one argument; this macro is very similar in format to
math-defsimplify. The main difference is that
here body is the body of a function with a single
argument u which is bound to the argument to the
function being integrated, not the function call itself.
Also, the variable of integration is available as
math-integ-var. If evaluation of the integral
requires doing further integrals, the body should call
‘(math-integral x)’ to
find the integral of x with respect to
math-integ-var; this function returns
nil if the integral could not be done. Some
examples:
(math-defintegral calcFunc-conj
(let ((int (math-integral u)))
(and int
(list 'calcFunc-conj int))))
(math-defintegral calcFunc-cos
(and (equal u math-integ-var)
(math-from-radians-2 (list 'calcFunc-sin u))))
In the cos example, we define only the
integral of ‘cos(x) dx’, relying on
the general integration-by-substitution facility to handle
cosines of more complicated arguments. An integration rule
should return nil if it can’t do the
integral; if several rules are defined for the same function,
they are tried in order until one returns a
non-nil result.
Define a rule for integrating a function or functions of
two arguments. This is exactly analogous to
math-defintegral, except that body is
written as the body of a function with two arguments,
u and v.
Attempt to solve the equation ‘lhs
= rhs’ by isolating the variable
var on the lefthand side; return the resulting
righthand side, or nil if the equation cannot be
solved. The variable var must appear at least once
in lhs or rhs. Note that the return
value is a formula which does not contain var;
this is different from the user-level solve and
finv functions, which return a rearranged
equation or a functional inverse, respectively. If
full is non-nil, a full solution
including dummy signs and dummy integers will be produced.
User-defined inverses are provided as properties in a manner
similar to derivatives:
(put 'calcFunc-ln 'math-inverse
(function (lambda (x) (list 'calcFunc-exp x))))
This function can call ‘(math-solve-get-sign x)’ to create a new arbitrary sign variable, returning x times that sign, and ‘(math-solve-get-int x)’ to create a new arbitrary integer variable multiplied by x. These functions simply return x if the caller requested a non-“full” solution.
This version of solve-for takes an expression
which will typically be an equation or inequality. (If it is
not, it will be interpreted as the equation
‘expr = 0’.) It returns
an equation or inequality, or nil if no solution
could be found.
This function solves a system of equations. Generally, exprs and vars will be vectors of equal length. See Solving Systems of Equations, for other options.
Returns a non-nil value if var
occurs as a subexpression of expr.
This function might seem at first to be identical to
calc-find-sub-formula. The key difference is
that expr-contains uses equal to
test for matches, whereas calc-find-sub-formula
uses eq. In the formula ‘f(a,
a)’, the two ‘a’s will
be equal but not eq to each
other.
Returns the number of occurrences of var as a
subexpression of expr, or nil if
there are no occurrences.
Returns true if expr refers to any variable the occurs in var. In other words, it checks if expr and var have any variables in common.
Return true if expr contains any variables, or
nil if expr contains only constants
and functions with constant arguments.
Returns a copy of expr, with all occurrences of
old replaced by new. This treats
lambda forms specially with respect to the dummy
argument variables, so that the effect is always to return
expr evaluated at old =
new.
This is like expr-subst, except that
old and new are lists of expressions to
be substituted simultaneously. If one list is shorter than
the other, trailing elements of the longer list are
ignored.
Returns the “weight” of expr, basically a count of the total number of objects and function calls that appear in expr. For “primitive” objects, this will be one.
Returns the “height” of expr, which is the deepest level to which function calls are nested. (Note that ‘a + b’ counts as a function call.) For primitive objects, this returns zero.
Check if expr is a polynomial in variable (or
sub-expression) var. If so, return the degree of
the polynomial, that is, the highest power of var
that appears in expr. For example, for
‘(x^2 + 3)^3 + 4’ this would return
6. This function returns nil unless
expr, when expanded out by a x
(calc-expand), would consist of a sum of terms
in which var appears only raised to nonnegative
integer powers. Note that if var does not occur in
expr, then expr is considered a
polynomial of degree 0.
Check if expr is a polynomial in variable or
sub-expression var, and, if so, return a list
representation of the polynomial where the elements of the
list are coefficients of successive powers of var:
‘a + b x + c
x^3’ would produce the list
‘(a b 0
c)’, and ‘(x +
1)^2’ would produce the list ‘(1 2
1)’. The highest element of the list will be
non-zero, with the special exception that if expr
is the constant zero, the returned value will be
‘(0)’. Return nil if
expr is not a polynomial in var. If
degree is specified, this will not consider
polynomials of degree higher than that value. This is a good
precaution because otherwise an input of
‘(x+1)^1000’ will cause a huge
coefficient list to be built. If loose is
non-nil, then a looser definition of a
polynomial is used in which coefficients are no longer
required not to depend on var, but are only
required not to take the form of polynomials themselves. For
example, ‘sin(x) x^2 + cos(x)’ is a
loose polynomial with coefficients
‘((calcFunc-cos x) 0 (calcFunc-sin
x))’. The result will never be nil
in loose mode, since any expression can be interpreted as a
“constant” loose polynomial.
Check if expr is a polynomial in any variable
that occurs in it; if so, return that variable. (If
expr is a multivariate polynomial, this chooses
one variable arbitrarily.) If pred is specified,
it should be a Lisp function which is called as
‘(pred
subexpr)’, and which should return
true if mpb-top-expr (a global name for the
original expr) is a suitable polynomial in
subexpr. The default predicate uses
‘(polynomial-p mpb-top-expr
subexpr)’; you can use
pred to specify additional conditions. Or, you
could have pred build up a list of every suitable
subexpr that is found.
Simplify polynomial coefficient list poly by (destructively) clipping off trailing zeros.
Mix two polynomial lists a and b (in
the form returned by is-polynomial) in a linear
combination with coefficient expressions ac and
bc. The result is a (not necessarily simplified)
polynomial list representing ‘ac
a + bc b’.
Multiply two polynomial coefficient lists a and b. The result will be in simplified form if the inputs were simplified.
Construct a Calc formula which represents the polynomial
coefficient list poly applied to variable
var. The a c
(calc-collect) command uses
is-polynomial to turn an expression into a
coefficient list, then build-polynomial-expr to
turn the list back into an expression in regular form.
Check if var is a variable which can be
interpreted as a unit name. If so, return the units table
entry for that unit. This will be a list whose first element
is the unit name (not counting prefix characters) as a symbol
and whose second element is the Calc expression which defines
the unit. (Refer to the Calc sources for details on the
remaining elements of this list.) If var is not a
variable or is not a unit name, return nil.
Return true if expr contains any variables
which can be interpreted as units. If sub-exprs is
t, the entire expression is searched. If
sub-exprs is nil, this checks whether
expr is directly a units expression.
Check whether expr contains exactly one units
variable. If so, return the units table entry for the
variable. If expr does not contain any units,
return nil. If expr contains two or
more units, return the symbol wrong.
Convert units expression expr to base units. If
which is nil, use Calc’s native
base units. Otherwise, which can specify a units
system, which is a list of two-element lists, where the first
element is a Calc base symbol name and the second is an
expression to substitute for it.
Return a copy of expr with all units variables replaced by ones. This expression is generally normalized before use.
Return a copy of expr with everything but units variables replaced by ones.
Next: Formatting Lisp Functions, Previous: Vector Lisp Functions, Up: Internals [Contents][Index]